package fhjoanneum.itm11.antesk.simplehack;

public abstract class Character
{
	// Members -----------------------------------------------------------
	protected String name;
	protected double hitpoints;
	protected Tile position;
	protected String test; // representation string for printMap
	protected int atk; // damage multiplier
	protected double ac; // damage reduction percentage
	protected double hit_chance; // percent chance to hit
	private int level;
	private int exp;
	protected Level level_class = new Level(this);
	private Handler handler = Handler.getInstance();
	private Dice dice = new Dice(5,20);
	
	// Constructors ------------------------------------------------------
	public Character(){}
	public Character(Tile position){}
	
	// Methods ===========================================================
	
	// Getters and setters -----------------------------------------------
	public String getTest(){return this.test;}
	public void setTest(String test){this.test = test;}
	public double getHitpoints(){return this.hitpoints;}
	public void setHitpoints(double hp){this.hitpoints = hp;}
	public void changeHitpoints(double hp){
		this.hitpoints = this.hitpoints + hp;}
	public String getName(){return this.name;}
	public void setName(String name){this.name = name;}
	public int getAtk(){return atk;}
	public void setAtk(int atk){this.atk = atk;}
	public double getAc(){return ac;}
	public void setAc(double d){this.ac = d;}
	public double getHitChance(){return hit_chance;}
	public void setHitChance(double hit_chance){
		this.hit_chance = hit_chance;}
	public Tile getPosition(){return this.position;}
	public void setPosition(Tile position){this.position = position;}
	public int getLevel(){return level;}
	public void setLevel(int level){this.level = level;}
	public int getExp(){return exp;}
	public void setExp(int exp){this.exp = exp;}
	
	// Move method for the character -------------------------------------
	// Also contains the test for any item, event or other entity on
	// the current tile after the character has moved
	public boolean move(Direction direction)
	{
		if(position.getNeighbor(direction).isEntryPossible() == true)
		{
			position.setCharacter(null);
			position = position.getNeighbor(direction);
			position.setCharacter(this);
			
			System.out.println("You move " + direction);
			
			// Test for entities on Tile *************************************
			if(position.getItem() != null)
			{
				PlayerCharacter pc = (PlayerCharacter) this;
				
				System.out.println("You found a " + 
						position.getItem().getName() + "!");
				pc.getInventory().addItem(position.getItem());
				position.setItem(null);
			}
			else if(position.getEvent() != null)
			{
				getPosition().getEvent().onEntry(this);
				getPosition().setEvent(null);
			}
			// Test for entities on Tile *************************************
			
			return true;
		}
		else
		{
			System.out.println("You cannot move there");
			return false;
		}
	}
	
	// Show stats method -------------------------------------------------
	public void showStats()
	{
		String suffix;
		
		if( (handler.playerPosition() % 10) == 1){suffix = "st";}
		else if( (handler.playerPosition() % 10) == 2){suffix = "nd";}
		else if( (handler.playerPosition() % 10) == 3){suffix = "rd";}
		else{suffix = "th";}
		
		System.out.println("Name: " + getName() + 
				"\nLevel: " + getLevel() +	
				"\nExp: " + getExp() + 
				"\nHP: " + (int)getHitpoints() + 
				"\nDamage: " + atk + "x("+dice.getMin()+"-"+dice.getMax()+")" +
				"\nHit Chance: " + (int)(hit_chance*100) + "%" + 
				"\nDamage Absorption: " + (int)(ac*100) + "%" +
				"\nPosition: " + handler.playerPosition() + suffix + " Tile");
	}	
	
	// Attack method -----------------------------------------------------
	public boolean attack(Direction direction)
	{
		position.setCharacter(this); // bugfix for initialization error
		
		Character enemy = position.getNeighbor(direction).getCharacter();		
		
		if(enemy == null) // no character in attacking direction
		{
			if(getPosition().getNeighbor(direction).getTileType() == 
					TileType.WALL)
			{
				System.out.println("You hit the wall and hurt yourself for " +
						"1 HP.");
				changeHitpoints(-1);
				return false;
			}
			else
			{
				System.out.println(getName() + "'s swift strikes only " +
						"hurt the air.");
				return false;
			}
		}
		
		int attack_value = dice.roll() * getAtk(); // attack_value
		
		// Basic hit test
		if(dice.random() + getHitChance() >= 1) // on hit
		{
			enemy.setHitpoints(enemy.getHitpoints() - 
					Math.round(attack_value*(1 - enemy.getAc())));
		}
		else // on miss
		{
			System.out.println(getName() + " misses " + enemy.getName());
			return false;
		}
		
		// Attack method
		if(enemy.getHitpoints() <= 0) // death check
		{
			System.out.println(name + " hits for " + attack_value + 
					" damage. " + enemy.getName() + " dies.");
			level_class.addExp(enemy.getExp()); // adds enemy exp to player
			enemy.getPosition().setCharacter(null);
			enemy.setPosition(null);
		}
		else // regular attack if not dead
		{
			int absorbed = (int)(Math.round(attack_value * enemy.getAc()));
			int actual_damage = 
					(int)(Math.round(attack_value*(1 - enemy.getAc())));
			
			System.out.print(name + " hits " + enemy.getName() + 
					" for " + actual_damage + " damage.");
			if(absorbed == 0)
			{
				System.out.println();
			}
			else
			{
				System.out.println(" (" + absorbed + " absorbed)");
			}	
		}
		return true;
	}
	
	// Open method -------------------------------------------------------
	/// No key to open doors defined in this version, so locked means 
	/// locked
	public boolean open(Direction direction)
	{
		try
		{
			DoorTile door = (DoorTile) getPosition().getNeighbor(direction);
			
			if(door.getOpened() == false && door.getLocked() == false)
			{
				door.setOpened(true);
				System.out.println("You open the door. (It was not locked)");
			}
			else if(door.getOpened() == false && door.getLocked() == true)
			{
				System.out.println("The door is locked. You don't seem to " +
						"hold the key.");
			}
			else if(door.getOpened() == true)
			{
				System.out.println("The door is already open.");
			}
		}
		catch(Exception e)
		{
			System.out.println("There is no door in this direction.");	
		}
		
		return true;
	}
}
